/** This class creates a new Client-Socket and communices with this client 
 *  @author ChrM and Sun Microsystems */

package info.chrm.jtalkerserver;

import info.chrm.helper.*;
import java.net.*;
import java.io.*;

public class JTalkerServerThread extends Thread {
    public Socket socket = null;
    public JTalkerServer parent;
    private boolean hasValidMemberConnection = false; // is a real member connected?
    private PrintWriter out = null;
    private static int MAX_PACKET_SIZE = 410000;
    
    /** Constructor */
    public JTalkerServerThread(JTalkerServer _parent, Socket _socket) {
      super("JTalkerServerThread");
      this.parent = _parent;
      this.socket = _socket;

    }

    /** Gets Connections infos */
    public String getConnectionInfo() {
       String retVal = "TCP/IP: " + this.socket.getInetAddress().getHostAddress();
       retVal += ":" + this.socket.getPort();

       /*if(this.getMember() != null)
	 retVal += " / Name: " + this.getMember().getUserName();
       
       retVal += " / #: " + this.parent.getNumOfMembers();*/
       return retVal;
    }

    /** Gets current member */
    public JTalkerMember getMember() {
       return this.parent.getMember(this.socket);
    }

    /** Sends the update request */
    public void sendUpdateRequest() {
        String message = JTalkerProtocol.getProcessString(5);
        this.getLogger().write("+ Sending update msg to: " + getMember().getUserName());
        this.out.println(message);	    
    }


    public void run() {
      try {
       this.out = new PrintWriter(socket.getOutputStream(), true);
       BufferedReader in = new BufferedReader( new InputStreamReader(socket.getInputStream()) );

       String inputLine, outputLine;
       JTalkerProtocol jtp = new JTalkerProtocol(this);
       outputLine = jtp.processInput(null);
       this.out.println(outputLine);      
       
       // Notify connection
       this.getLogger().write("(+) CONNECT: " + this.getConnectionInfo());

       
       try { 
	  while ((inputLine = in.readLine()) != null) {
            if(inputLine.length() > MAX_PACKET_SIZE) {
            if(this.getMember() != null) {
	        this.getLogger().write("*** Message to big (" + inputLine.length() + " / max=" + MAX_PACKET_SIZE + ") from " + this.getMember().getUserInfo() + ". Close connection.");
            }
	        this.closeConnection(in, this.out);
                return;
            }

	    outputLine = jtp.processInput(inputLine);
	    this.out.println(outputLine);	    
	    
	    if(jtp.closeConnectionNow) {
	       this.closeConnection(in, this.out);
	       this.getLogger().write("+ Protocol ends - close connection.");
	       return;
	    }

	    // Real Member connects!
	    if(this.getMember() != null) {	    
	       // Update Session ID
	       this.getMember().updateSessionID();
               this.getMember().setThread(this);
	 
	       // Notify login
	       if(!this.hasValidMemberConnection) {
		  this.getLogger().write("+ MEMBER login: " + this.getMember().getUserInfo());
		  this.getLogger().write("+ Number of connected members: " + this.parent.getNumOfMembers());
                  this.parent.sendUpdateRequestToAll(null);
		  this.hasValidMemberConnection = true;
	       }
	    }
	  }
       } catch (Exception _e) {
	  this.getLogger().write("+ Client died... Exception: " + _e.toString());
	  _e.printStackTrace();
	  //this.closeConnection(in, out);
       } 
      
       this.closeConnection(in, this.out);

      } catch (IOException _e) {
	 this.getLogger().writeError("*** IOError Error in client thread (maybe a scan?): " + _e.toString());
      }
    }

    /** Close this socket */
    private void closeConnection(BufferedReader _in, PrintWriter _out) {
       try {
	 _out.close();
	 _in.close();
	 
	 this.getLogger().write("(-) DISCONNECT: " + this.getConnectionInfo());
	 
	 // Don't remove webclients!!!
	 if(this.getMember() != null) {
	    // Notify login
	    this.getLogger().write("- MEMBER logout: " + this.getMember().getUserInfo());
	    this.getLogger().write("- Number of connected members: " + (this.parent.getNumOfMembers() - 1));
	    
	    if(!this.getMember().getUserType().equals(JTalkerMember.USER_TYPE_WEBCLIENT))
	       this.parent.removeMember(this.socket.getPort());
	    else
	       this.getMember().isOnline = false;
	 }
       
	 this.socket.close();
	 
       } catch (Exception _e) { 
	  this.getLogger().writeError("*** Runtime Error: Can't close connection: " + _e.getMessage());
	  _e.printStackTrace();
       } 
                  
       this.parent.sendUpdateRequestToAll(null);
    }

    /** Gets the logger - passthru from parent */
    public Logger getLogger() {
       return this.parent.getLogger();
    }
}
